home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 85 / CD Temático 40 Febrero 2004.iso / DOS / testdisk / src / fat_dir.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-01-09  |  12.0 KB  |  365 lines

  1. /*
  2.  
  3.     File: dir_fat.c
  4.  
  5.     Copyright (C) 1998-2004 Christophe GRENIER <grenier@cgsecurity.org>
  6.   
  7.     This software is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.   
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.   
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <ctype.h>    /* toupper */
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <time.h>
  28. #include <sys/stat.h>
  29. #include <unistd.h>
  30. #include "types.h"
  31. #include "common.h"
  32. #include "fat.h"
  33. #include "lang.h"
  34. #include "fnctdsk.h"
  35. #include "testdisk.h"
  36. #include "intrface.h"
  37. #include "dir.h"
  38. #include "fat_dir.h"
  39.  
  40. static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len);
  41.  
  42. static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len)
  43. {
  44.     while (len--) {
  45.         *dst++ = src[0] | (src[1] << 8);
  46.         src += 2;
  47.     }
  48. }
  49.  
  50. t_file_data *dir_fat_aux(const char*buffer, const unsigned int size, const unsigned int cluster_size)
  51. {
  52.   const struct msdos_dir_entry *de=(const struct msdos_dir_entry*)buffer;
  53.   wchar_t unicode[1000];
  54.   unsigned char long_slots;
  55.   t_file_data *dir_list=NULL;
  56.   t_file_data *current_file=NULL;
  57. GetNew:
  58.   long_slots = 0;
  59.   unicode[0]=0;
  60.   if (de->name[0] == (__s8) DELETED_FLAG)
  61.     goto RecEnd;
  62.   if (de->attr == ATTR_EXT) {
  63.     unsigned int i;
  64.     const struct msdos_dir_slot *ds;
  65.     unsigned char id;
  66.     unsigned char slot;
  67.     unsigned char slots;
  68.     unsigned char sum;
  69.     unsigned char alias_checksum;
  70. ParseLong:
  71.     slots = 0;
  72.     ds = (const struct msdos_dir_slot *) de;
  73.     id = ds->id;
  74.     if ((id & 0x40)==0)
  75.       goto RecEnd;
  76.     slots = id & ~0x40;
  77.     if (slots > 20 || slots==0)    /* ceil(256 * 2 / 26) */
  78.       goto RecEnd;
  79.     long_slots = slots;
  80.     alias_checksum = ds->alias_checksum;
  81.  
  82.     slot = slots;
  83.     while (1) {
  84.       int offset;
  85.  
  86.       slot--;
  87.       offset = slot * 13;
  88.       fat16_towchar(unicode + offset, ds->name0_4, 5);
  89.       fat16_towchar(unicode + offset + 5, ds->name5_10, 6);
  90.       fat16_towchar(unicode + offset + 11, ds->name11_12, 2);
  91.  
  92.       if ((ds->id & 0x40)!=0) {
  93.     unicode[offset + 13] = 0;
  94.       }
  95.       de++;
  96.       if((const void*)de>=(const void*)(buffer+size))
  97.     goto EODir;
  98.       if (slot == 0)
  99.     break;
  100.       ds = (const struct msdos_dir_slot *) de;
  101.       if (ds->attr !=  ATTR_EXT)
  102.     goto RecEnd;    /* XXX */
  103.       if ((ds->id & ~0x40) != slot)
  104.     goto ParseLong;
  105.       if (ds->alias_checksum != alias_checksum)
  106.     goto ParseLong;
  107.     }
  108.     if (de->name[0] == (__s8) DELETED_FLAG)
  109.       goto RecEnd;
  110.     if (de->attr ==  ATTR_EXT)
  111.       goto ParseLong;
  112.     if (IS_FREE(de->name) || ((de->attr & ATTR_VOLUME)!=0))
  113.       goto RecEnd;
  114.     for (sum = 0, i = 0; i < 11; i++)
  115.       sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
  116.     if (sum != alias_checksum)
  117.       long_slots = 0;
  118.   }
  119. RecEnd:
  120.   if((unicode[0]==0) &&(de->attr != ATTR_EXT))
  121.   { /* short name 8.3 */
  122.     int i;
  123.     int j=0;
  124.     for(i=0;(i<8)&&(de->name[i]!=' ');i++)
  125.       unicode[j++]=de->name[i];
  126.     if(de->ext[0]!=' ')
  127.     {
  128.       unicode[j++]='.';
  129.       for(i=0;(i<3)&&(de->ext[i]!=' ');i++)
  130.     unicode[j++]=de->ext[i];
  131.     }
  132.     unicode[j]=0;
  133.   }
  134.   if (((de->attr != ATTR_EXT)||(long_slots!=0)) && ((__s8) unicode[0] != (__s8) DELETED_FLAG) && !(de->attr & ATTR_VOLUME))
  135.   {
  136.     if(unicode[0]!=0)
  137.     {
  138.       unsigned int i;
  139.       t_file_data *new_file=MALLOC(sizeof(*new_file));
  140.       for(i=0;(unicode[i]!=0)&&(i<sizeof(new_file->name)-1);i++)
  141.     new_file->name[i]=(char) unicode[i];
  142.       new_file->name[i]=0;
  143.       new_file->filestat.st_dev=0;
  144.       new_file->filestat.st_ino=(de->starthi<<16)|de->start;
  145.       new_file->filestat.st_mode = MSDOS_MKMODE(de->attr,(LINUX_S_IRWXUGO & ~(LINUX_S_IWGRP|LINUX_S_IWOTH)));
  146.       new_file->filestat.st_nlink=0;
  147.       new_file->filestat.st_uid=0;
  148.       new_file->filestat.st_gid=0;
  149.       new_file->filestat.st_rdev=0;
  150.       new_file->filestat.st_size=de->size;
  151.       new_file->filestat.st_blksize=cluster_size;
  152. #ifndef DJGPP
  153.       if(new_file->filestat.st_blksize!=0)
  154.       {
  155.     new_file->filestat.st_blocks=(new_file->filestat.st_size+new_file->filestat.st_blksize-1)/new_file->filestat.st_blksize;
  156.       }
  157. #endif
  158.       new_file->filestat.st_atime=new_file->filestat.st_ctime=new_file->filestat.st_mtime=date_dos2unix(de->time,de->date);
  159.       new_file->prev=current_file;
  160.       new_file->next=NULL;
  161.       /* ecrit_rapport("fat: new file %s de=%p size=%u\n",new_file->name,de,de->size); */
  162.       /*    fat_write_rapport(new_fat_element); */
  163.       if(current_file!=NULL)
  164.     current_file->next=new_file;
  165.       else
  166.     dir_list=new_file;
  167.       current_file=new_file;
  168.     }
  169.     else
  170.     {
  171.       return dir_list;
  172.     }
  173.   }
  174.   de++;
  175.   if((const void *)de<(const void *)(buffer+size))
  176.     goto GetNew;
  177. EODir:
  178.   return dir_list;
  179. }
  180.  
  181. static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
  182.           /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
  183.  
  184. /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
  185.  
  186. int date_dos2unix(const unsigned short f_time, const unsigned short f_date)
  187. {
  188.     int month,year,secs;
  189.  
  190.     /* first subtract and mask after that... Otherwise, if
  191.        f_date == 0, bad things happen */
  192.     month = ((f_date >> 5) - 1) & 15;
  193.     year = f_date >> 9;
  194.     secs = (f_time & 31)*2+60*((f_time >> 5) & 63)+(f_time >> 11)*3600+86400*
  195.         ((f_date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
  196.         month < 2 ? 1 : 0)+3653);
  197.             /* days since 1.1.70 plus 80's leap day */
  198.     return secs;
  199. }
  200.  
  201. t_file_data *fat12_dir(t_param_disk *disk_car, const t_diskext *partition, t_dir_data *dir_data, const unsigned long int first_cluster)
  202. {
  203.   struct fat_boot_sector*fat_header=(struct fat_boot_sector*)dir_data->private_dir_data;
  204.   if(fat_header->cluster_size<1)
  205.   {
  206.       ecrit_rapport(msg_ROOT_CLUSTER_RERR);
  207.       return NULL;
  208.     }
  209.   if(first_cluster==0)
  210.     return fat1x_rootdir(disk_car,partition,dir_data->debug,fat_header);
  211.   {
  212.     t_file_data *dir_list;
  213.     unsigned int cluster_size=fat_header->cluster_size;
  214.     unsigned char *buffer_dir=MALLOC(SECTOR_SIZE*cluster_size*5);
  215.     unsigned int cluster;
  216.     unsigned int nbr_cluster;
  217.     memset(buffer_dir,0,SECTOR_SIZE*cluster_size*5);
  218.     for(cluster=first_cluster, nbr_cluster=0;
  219.     ((cluster&0x0ff8)!=(unsigned)0x0ff8) && (cluster>=2) && (nbr_cluster<5);
  220.     cluster=get_next_cluster(disk_car,partition, UP_FAT12,le16(fat_header->reserved), cluster), nbr_cluster++)
  221.     {
  222.       dword start=partition->lba+le16(fat_header->reserved)+fat_header->fats*le16(fat_header->fat_length)+(get_dir_entries(fat_header)*32+SECTOR_SIZE-1)/SECTOR_SIZE+(cluster-2)*cluster_size;
  223.       if(dir_data->debug)
  224.     ecrit_rapport("FAT12 cluster=%u(0x%x), pos=%lu\n",cluster,cluster,start);
  225.       if(disk_car->read(disk_car, cluster_size, buffer_dir+SECTOR_SIZE*cluster_size*nbr_cluster, start))
  226.       {
  227.     ecrit_rapport(msg_ROOT_CLUSTER_RERR);
  228.     FREE(buffer_dir);
  229.     return NULL;
  230.       }
  231.     }
  232.     dir_list=dir_fat_aux(buffer_dir,SECTOR_SIZE*cluster_size*nbr_cluster,cluster_size);
  233.     FREE(buffer_dir);
  234.     return dir_list;
  235.   }
  236. }
  237.  
  238. t_file_data *fat16_dir(t_param_disk *disk_car, const t_diskext *partition, t_dir_data *dir_data, const unsigned long int first_cluster)
  239. {
  240.   struct fat_boot_sector*fat_header=(struct fat_boot_sector*)dir_data->private_dir_data;
  241.   if(fat_header->cluster_size<1)
  242.   {
  243.     ecrit_rapport(msg_ROOT_CLUSTER_RERR);
  244.     return NULL;
  245.   }
  246.   if(first_cluster==0)
  247.     return fat1x_rootdir(disk_car,partition,dir_data->debug,fat_header);
  248.   {
  249.     t_file_data *dir_list=NULL;
  250.     unsigned int cluster_size=fat_header->cluster_size;
  251.     unsigned char *buffer_dir=MALLOC(SECTOR_SIZE*cluster_size*5);
  252.     unsigned int cluster;
  253.     unsigned int nbr_cluster;
  254.     memset(buffer_dir,0,SECTOR_SIZE*cluster_size*5);
  255.     /* Need to correct the test */
  256.     for(cluster=first_cluster, nbr_cluster=0;
  257.     ((cluster&0xfff8)!=(unsigned)0xfff8) && (cluster>=2) && (nbr_cluster<5);
  258.     cluster=get_next_cluster(disk_car,partition, UP_FAT16,le16(fat_header->reserved), cluster), nbr_cluster++)
  259.     {
  260.       dword start=partition->lba+le16(fat_header->reserved)+fat_header->fats*le16(fat_header->fat_length)+(get_dir_entries(fat_header)*32+SECTOR_SIZE-1)/SECTOR_SIZE+(cluster-2)*cluster_size;
  261.       if(dir_data->debug)
  262.     ecrit_rapport("FAT16 cluster=%u(0x%x), pos=%lu\n",cluster,cluster,start);
  263.       if(disk_car->read(disk_car, cluster_size, buffer_dir+SECTOR_SIZE*cluster_size*nbr_cluster, start))
  264.       {
  265.     ecrit_rapport(msg_ROOT_CLUSTER_RERR);
  266.     FREE(buffer_dir);
  267.     return NULL;
  268.       }
  269.     }
  270.     dir_list=dir_fat_aux(buffer_dir,SECTOR_SIZE*cluster_size*nbr_cluster,cluster_size);
  271.     FREE(buffer_dir);
  272.     return dir_list;
  273.   }
  274. }
  275.  
  276. t_file_data *fat32_dir(t_param_disk *disk_car, const t_diskext *partition, t_dir_data *dir_data, const unsigned long int first_cluster)
  277. {
  278.   struct fat_boot_sector*fat_header=(struct fat_boot_sector*)dir_data->private_dir_data;
  279.   if(fat_header->cluster_size==0 || le32(fat_header->root_cluster)==0)
  280.     return NULL;
  281.   {
  282.     t_file_data *dir_list;
  283.     unsigned int cluster_size=fat_header->cluster_size;
  284.     unsigned char *buffer_dir=MALLOC(SECTOR_SIZE*cluster_size*5);
  285.     unsigned int cluster;
  286.     int nbr_cluster;
  287.     memset(buffer_dir,0,SECTOR_SIZE*cluster_size*5);
  288.     /* Need to correct the test */
  289.     for(cluster=(first_cluster==0?le32(fat_header->root_cluster):first_cluster), nbr_cluster=0;
  290.     ((cluster&0xffffff8)!=(unsigned)0xffffff8) && (cluster>=2) && (nbr_cluster<5);
  291.     cluster=get_next_cluster(disk_car,partition, UP_FAT32,le16(fat_header->reserved), cluster), nbr_cluster++)
  292.     {
  293.       dword start=partition->lba+le16(fat_header->reserved)+fat_header->fats*le32(fat_header->fat32_length)+(cluster-2)*cluster_size;
  294.       if(dir_data->debug)
  295.     ecrit_rapport("FAT32 cluster=%u(0x%x), pos=%lu\n",cluster,cluster,start);
  296.       if(disk_car->read(disk_car, cluster_size, buffer_dir+SECTOR_SIZE*cluster_size*nbr_cluster, start))
  297.       {
  298.     ecrit_rapport(msg_ROOT_CLUSTER_RERR);
  299.     FREE(buffer_dir);
  300.     return 0;
  301.       }
  302.     }
  303.     dir_list=dir_fat_aux(buffer_dir,SECTOR_SIZE*cluster_size*5,cluster_size);
  304.     FREE(buffer_dir);
  305.     return dir_list;
  306.   }
  307. }
  308.  
  309.  
  310. t_file_data *fat1x_rootdir(t_param_disk *disk_car, const t_diskext *partition, const int debug, struct fat_boot_sector*fat_header)
  311. {
  312.   unsigned int root_size=(get_dir_entries(fat_header)-1)/16+1;
  313.   dword start=0;
  314.   if(debug>1)
  315.   {
  316.     ecrit_rapport("fat1x_rootdir root_size=%u\n",root_size);
  317.   }
  318.   {
  319.     unsigned char *buffer_dir=(unsigned char*)MALLOC(SECTOR_SIZE*root_size);
  320.     start=partition->lba+le16(fat_header->reserved)+fat_header->fats*le16(fat_header->fat_length);
  321.     if(disk_car->read(disk_car, root_size, buffer_dir, start))
  322.     {
  323.       ecrit_rapport("FAT 1x");
  324.       ecrit_rapport(msg_ROOT_CLUSTER_RERR);
  325.       return NULL;
  326.     }
  327.     return dir_fat_aux(buffer_dir,SECTOR_SIZE*root_size,fat_header->cluster_size);
  328.   }
  329. }
  330.  
  331. int dir_partition_fat_aux(WINDOW *window,t_param_disk *disk_car, t_diskext *partition, const int debug, struct fat_boot_sector*fat_header)
  332. {
  333.   t_dir_data dir_data;
  334.   dir_data.window=window;
  335.   dir_data.debug=debug;
  336.   dir_data.private_dir_data=fat_header;
  337.   switch(partition->upart_type)
  338.   {
  339.     case UP_FAT12:
  340.       dir_data.get_dir=fat12_dir;
  341.       break;
  342.     case UP_FAT16:
  343.       dir_data.get_dir=fat16_dir;
  344.       break;
  345.     case UP_FAT32:
  346.       dir_data.get_dir=fat32_dir;
  347.       break;
  348.     default:
  349.       return -1;
  350.   }
  351.   strncpy(dir_data.current_directory,"/",sizeof(dir_data.current_directory));
  352.   return dir_partition(disk_car,partition,&dir_data,0);
  353. }
  354.  
  355. int dir_partition_fat(WINDOW *window,t_param_disk *disk_car, t_diskext *partition, const int debug)
  356. {
  357.   t_sector buffer;
  358.   if(disk_car->read(disk_car,1, &buffer, partition->lba+partition->boot_sector))
  359.   {
  360.     ecrit_rapport(msg_CHKFAT_RERR); return 1;
  361.   }
  362.   dir_partition_fat_aux(window,disk_car, partition, debug, (struct fat_boot_sector*)buffer);
  363.   return 0;
  364. }
  365.